A DLL REVERSING EXAMPLE - HOW TO RECONFIGURE EXPLORER.EXE'S BEHAVIOUR MODIFYING SOME FUNCTIONS 
IN THE SHELL32.DLL LIBRARY

By -NeuRaL_NoiSE

_______________________________________________________________________________________________


Hi everyone!

How many times have u thought "damn wouldn't it be nice if i could delete files from hard disk 
without having them pass through Recycle folder first...i could set the option 'move to 
recycle' (in the recycled preferences) off but then i wouldn't have a chance to choose wheter i 
want to erase the file or to move it to the trashcan...or i could press the shift while hitting 
del to erase the file from disk but then that poor neural_n dude wouldn't have a fair chance to 
write a tutorial..." ??? Well, if u have this problem (hmmm:), you're reading the right 
.txt :) 

at this point, let me explain a coupla things and let me disclaim my responsabilities:

FIRST : If u act like i point out in this tute, don't consider me responsible for any loss of 
data that might occur on your hard disk (your "DELETE" command on explorer won't be as safe as 
the old times anymore! :)

SECOND : this is more a reversing tutorial than a cracking one...if u are reading this hoping 
to find out how to deprotect some game or app i must tell you that alas u won't find any of the 
such here. If u're looking for this kinda stuff, please refer to many of the fantastic web 
pages around (first of all try out some links at fravia.org).

THIRD : I have a little problem writing this tutorial. I am italian, and obviously my copy of 
Window$ is in italian...being shell32.dll a system dll, its language will be different from 
nation to nation. So i can't assure you that the VA's and the offsets i write in this tute will 
be the same on your computer (i don't really think anyway)...however you should be able to 
follow the procedure by printing the text and following with your disassembled copy on the 
screen, it's not such a difficult task. And i must point out two more IMPORTANT things:

 * THIS TUTORIAL IS WRITTEN FOR *WINDOWS 95 ONLY* - I STRONGLY THINK THAT ON WINDOWS 98 THE 
   SHELL32.DLL FILE IS DIFFERENT (EVEN THO I'M NOT SURE). MY OWN VERSION OF WINDOWS IS 
   4.00.950 B

 * TO FOLLOW THIS TUTORIAL, YOU *MUST* KEEP THE OPTION THAT MOVES THE FILES INTO THE RECYCLED
   INSTEAD OF ERASING THEM FROM DISK (YOU CONFIGURE THAT IN THE RECYCLED PREFERENCES). IN
   ITALIAN VERSIONS OF WINDOWS, YOU'LL HAVE A DIFFERENT DIALOG BOX IF YOU HAVE THIS OPTION
   ON/OFF. A FRIEND TOLD ME THAT IN ENGLISH YOU'LL ALWAYS HAVE THE SAME DIALOG, WHETHER THE 
   OPTION IS ON OR OFF. THAT'S WEIRD ACTUALLY :)

This said......LET'S GO!!!

so...as u will have surely noticed from the intro, in this tute i'll describe you how to create 
a situation where, when u choose an option, Window$ explorer will physically ERASE the files 
from your hd, whithout having them pass through recycled folder. Would you like a 3-options 
dialog box, ONE=MOVE TO RECYCLED, TWO=ERASE FROM DISK and THREE=CANCEL OPERATION ?
Right....i'm talking about combinating, in some mysterious way, the three things without having 
to play around with recycled preferences every single time, or hitting some shift key.
Ok, 'nuff chitchat....

Some ppl think that it's explorer.exe that does the tricks (deleting stuff from hd, copying 
files and so on), but that's only partly true. The code we will modify resides in the 
SHELL32.DLL library...a dll (Dynamic Link Library) is a set of functions that can come handy 
for executable files (in our case explorer.exe), and which is loaded/unloaded everytime the 
executable wishes (when it needs its functions, when it doesn't need them anymore and so on). 
The dll is also unloaded when you close the last program which used it. In our case, 
shell32.dll will always be present cuz the first copy of explorer (which is launched at windows 
start as u all know) loads it into memory, and you can't close that copy of explorer, because 
that would mean closing the session. Shell32.dll is in the WINDOWS\SYSTEM dir of your pc. No 
big deal, we'll treat the dll as a normal exe, so the tools we'll use will be the usual ones:

* W32Dasm v8.93
* SoftICE v3.24
* HIEW v6.01

Open Shell32.dll with W32dasm....you'll note the image base difference...not 40000000h anymore 
(as most of the classic .exe's) but 7FDB0000h. Good, now open Explorer.exe and create a 
temporary directory, filling it with useless files copied from other dirs. BE CAREFUL NOT TO 
OPERATE WITH DIRECTORIES ALREADY PRESENT ON YOUR HARD DISK, BECAUSE THE CHANCES OF LOSING YOUR 
DATA ARE VERY HIGH!
Ok...now take a random file from your dummy dir and choose DELETE from the FILE menu (or from 
the context menu that appears when u hit the right mouse button on the selected file). You'll 
have a nice dialog that will ask you if you want to delete the file...good, we found our hook 
to the code. At first look, the API to break on is DialogBoxParamA. So let's do it...choose 
"NO", enter SoftICE, and write "BPX DialogBoxParamA".
Select once again "delete" and sice will pop. Press F12 and you will see the dialog on your 
screen once again...select "YES" and sice will pop up again, and you will be at the line of 
code next to the Dialog Box call, which is this one:


* Reference To: USER32.DialogBoxParamA, Ord:0084h
                                  |
:7FDE2505 FF15E83DE17F            Call dword ptr [7FE13DE8]
:7FDE250B 83F8FF                  cmp eax, FFFFFFFF        ; <--YOU'LL BE HERE

Take a look at EAX register, which, as you know, contains the return value of EVERY API 
function.
Note that it's 6. Press F5, and your file will be moved to the recycled. Now choose DELETE once 
again. You'll note that, if you answer "NO", the return value in EAX after the call to 
DialogBoxParamA is 7. Repeat the operation, but this time press the ESCape key on your 
keyboard. The return value will be 2. At this point we can draw a little scheme:


  RETURN VALUE FROM DialogBoxParamA CALL   |   KEY/BUTTON SELECTED    |     ** MEANING **
___________________________________________|__________________________|________________________
                                           |                          |
          00000006                         |BUTTON "YES" ON THE DIALOG| MOVE FILE TO RECYCLED
___________________________________________|__________________________|________________________
                                           |                          |
          00000007                         | BUTTON "NO" ON THE DIALOG| CANCEL THE OPERATION 
___________________________________________|__________________________|________________________
                                           |                          |
          00000002                         | "ESC" KEY ON THE KEYBOARD| CANCEL THE OPERATION 
___________________________________________|__________________________|________________________



Hmm.....what bites here is a useless repetition....two return values perform the same 
function...it would be much better if we could modify the function of the "NO" button on the 
dialog box...perhaps even redirecting it towards the PHYSICAL ELIMINATION of the file from the 
disk....thus, without huge changes to the code we'd have a much more interesting situation: 
"YES" would move the file to the recycled folder, "NO" would phyisically eliminate it from 
disk, and "ESC" would cancel the operation. Let's see what we can do :)

We'll trace on with F10 in sice, until we don't arrive here:

* Referenced by a JUMP at Addresses:
|:7FDE24ED(U), :7FDE2519(C), :7FDE2524(U)
|
:7FDE252B 83FE06                  cmp esi, 00000006         ; ESI CONTAINS THE RETURN VALUE
:7FDE252E 751E                    jne 7FDE254E              ; IF YOU DIDN'T CHOOSE "YES"
:7FDE2530 8B452C                  mov eax, dword ptr [ebp+2C]  
:7FDE2533 8B00                    mov eax, dword ptr [eax]  ; OBJECT DESCRIPTOR'S INITIAL BYTE
:7FDE2535 A810                    test al, 10               ; CHECK IF THE OBJECT IS A DIR    
:7FDE2537 7515                    jne 7FDE254E              ; IF SO (10=DIR, 20=FILE) JUMP 
:7FDE2539 A805                    test al, 05               ; IF IT'S A FILE....
:7FDE253B 7411                    je 7FDE254E               ; JUMP AS WELL :)    

Stop! We have enough infos to understand that the procedure will continue, if everything is OK, 
at address 7FDE254E...where we find this line of code:

:7FDE254E 8BC6                    mov eax, esi

The return value is put in eax again, very good...we're on the right path...the previous check
was needed only to verify memory and handle problems...if there were problems, a dummy value 
was left into eax and next operations wouldn't have been executed. As you will see, shell32.dll 
is FULL of such checks...you can call it Good Old Micro$oft Redundant Code (TM) :)

Let's keep on tracing with SoftICE until we execute the "ret 028"...we'll find ourselves here:

:7FDE4093 E810E1FFFF              call 7FDE21A8         ; <-- WE COME BACK FROM THIS CALL
:7FDE4098 8BF8                    mov edi, eax

* Referenced by a JUMP at Address:
|:7FDE4064(C)
|
:7FDE409A 83FF06                  cmp edi, 00000006        ; AGAIN...CHECK IF WE PRESSED "YES"     
:7FDE409D 7540                    jne 7FDE40DF             ; OTHERWISE PROCESS ACCORDINGLY    
:7FDE409F 8B442434                mov eax, dword ptr [esp+34] 
:7FDE40A3 8B08                    mov ecx, dword ptr [eax] ; OBJ. DESCR. INITIAL BYTE IN ECX
:7FDE40A5 F6C110                  test cl, 10              ; HAVE WE GOT A FILE HERE??
:7FDE40A8 7435                    je 7FDE40DF              ; YES! JUMP!
:7FDE40AA 81FD00010000            cmp ebp, 00000100        ; OR A DIR?? (100=DIRECTORY)
:7FDE40B0 7408                    je 7FDE40BA
:7FDE40B2 81FD00030000            cmp ebp, 00000300        ; (300=FILE)
:7FDE40B8 7525                    jne 7FDE40DF        

Heh....more checks...(getting tired? Nah, there's still more to come :)...now our jne at 409D 
won't jump cuz we chose "YES", while we'll take the one at 40A8 for obvious reasons (we chose a 
file :)...now i must tell you one thing. What we are about to do is REALLY dangerous for your 
data. So I chose to cover, in this tutorial, ONLY the modifications of the code that perform 
SINGLE FILE elimination. If you want to delete MORE than one file at once, or a whole dir, 
you'll have to use shift or pass through the recycled...in other words, the file will be ERASED 
from disk by pressing "NO" ONLY when you are trying to eliminate ONE single file. However, if 
you are thinking about modifying the code relative to multiple stuff elimination, i'll give you 
a little advice: the dialog box is different (at least here in Italy :D) when you want to 
delete more files at once...so, a bpx on DialogBoxParamA will make sice pop in another code 
zone, and u'll find easy to proceed in the same way (or in a similar one) as we're doing here. 
Another little advice: when you delete more than one file at once, you can consider nopping out 
the "mov eax,2" that will be performed either when you press "NO" or when you press "ESC"...by 
nopping the mov you'll still have a differentiation between the two return values, and thus you 
will be able to process them accordingly in the dialog procedure. Only problem here is that i 
don't think there'll be enough space to insert your own code there, as we will have one less 
value (my god, where does Bill recruit his programmers ?! :) and the "7" value won't be 
processed. So, you might have to increase the size of the last section of the pe header and 
append your code there, but hey, that's quite another story :D - although i'm thinking about 
writing a tutorial for that as well, but i need some motivation...write me and tell me whether 
i should or not :))

Whatever, let's come back to our reversing session :)

The jumps point us to the next part of the code where our return value will be analized, in the 
case we chose a file (in other words, what we're interested in:)...it starts at 7FDE40DF:

:7FDE40DF 83FF02                  cmp edi, 00000002
:7FDE40E2 741A                    je 7FDE40FE
:7FDE40E4 83FF07                  cmp edi, 00000007
:7FDE40E7 7415                    je 7FDE40FE
:7FDE40E9 837C241C00              cmp dword ptr [esp+1C], 00000000
:7FDE40EE 740E                    je 7FDE40FE
:7FDE40F0 FF742424                push [esp+24]
:7FDE40F4 56                      push esi
:7FDE40F5 FF742434                push [esp+34]
:7FDE40F9 E845EEFFFF              call 7FDE2F43

* Referenced by a JUMP at Addresses:
|:7FDE40E2(C), :7FDE40E7(C), :7FDE40EE(C)
|
:7FDE40FE 8BC7                    mov eax, edi
:7FDE4100 5D                      pop ebp
:7FDE4101 5F                      pop edi
:7FDE4102 5E                      pop esi
:7FDE4103 5B                      pop ebx
:7FDE4104 83C418                  add esp, 00000018
:7FDE4107 C22400                  ret 0024


Three more checks...if we hit "ESC" or chose "NO", the program will exit from the call (with 
the ret 024 at 4107), keeping that value in the register, otherwise it executes another part of 
the code, in order to gain the necessary infos for the file elimination (with the call at 
40F9).
Let's keep on tracing with SoftICE, and we'll reach the caller....

:7FDE4952 E8A3F6FFFF              call 7FDE3FFA    ; <--WE COME FROM THIS CALL     
:7FDE4957 83F802                  cmp eax, 00000002 ; DID U PRESS "ESC" ?
:7FDE495A 0F847F080000            je 7FDE51DF        
:7FDE4960 83F806                  cmp eax, 00000006 ; DID U CHOOSE "YES" ?
:7FDE4963 743F                    je 7FDE49A4
:7FDE4965 83F807                  cmp eax, 00000007 ; DID U CHOOSE "NO" ?
:7FDE4968 0F8486070000            je 7FDE50F4

* Referenced by a JUMP at Addresses:
|:7FDE48D1(U), :7FDE50AF(U)
|
:7FDE496E 8945FC                  mov dword ptr [ebp-04], eax ; SORRY, BUT WE HAVE SOMETHING
                                                              ; WRONG HERE..IF EAX DOESN'T HOLD
                                                              ; ONE OF THE PREVIOUS 3 VALUES, 
                                                              ; WE HAVE AN INVALID HANDLE!
                                                              ; LET'S PRINT AN ERROR MESSAGE!               

Wohho! Here's the interesting code...the game gets more fun :D
Luck is by our side...we have three branches for three potential options...now the problem is 
redirecting the je relative to the "NO" button to a different piece of code, which will 
ELIMINATE the file from the disk...we won't have to waste time with pe sections raw and virtual 
sizes, and that's a good advantage!

For now, let's keep on tracing, just to get an idea of how things work...our run will deviate 
at 4963 cuz in our case we chose "YES"...and we'll find ourselves here:

:7FDE49A4 8B4DF4                  mov ecx, dword ptr [ebp-0C]
:7FDE49A7 8B01                    mov eax, dword ptr [ecx]
:7FDE49A9 0B45F8                  or eax, dword ptr [ebp-08]
:7FDE49AC 3D01020000              cmp eax, 00000201
:7FDE49B1 7725                    ja 7FDE49D8 ; WE TAKE THIS ONE IF WE'RE NOT PROCESSING A DIR
:7FDE49B3 0F8402020000            je 7FDE4BBB
:7FDE49B9 3D01010000              cmp eax, 00000101
:7FDE49BE 0F848E000000            je 7FDE4A52
:7FDE49C4 3D02010000              cmp eax, 00000102
:7FDE49C9 0F84FA000000            je 7FDE4AC9
:7FDE49CF 3D03010000              cmp eax, 00000103
:7FDE49D4 7447                    je 7FDE4A1D
:7FDE49D6 EB3E                    jmp 7FDE4A16

Don't be scared by the number of the jumps, if everything is ok you'll take the JA at 49B1 
(u won't take it if u're trying to delete a folder, but as soon as it comes to deleting the 
first file of such folder, you'll take it), that will bring you here:

:7FDE49D8 3D02020000              cmp eax, 00000202
:7FDE49DD 743E                    je 7FDE4A1D
:7FDE49DF 3D03020000              cmp eax, 00000203
:7FDE49E4 0F84D1010000            je 7FDE4BBB
:7FDE49EA 3D01030000              cmp eax, 00000301
:7FDE49EF 0F84F0030000            je 7FDE4DE5
:7FDE49F5 3D02030000              cmp eax, 00000302
:7FDE49FA 0F843C020000            je 7FDE4C3C
:7FDE4A00 3D03030000              cmp eax, 00000303
:7FDE4A05 0F8444030000            je 7FDE4D4F    ; JUMP THAT WILL BE TAKEN IF EVERYTHING IS OK
:7FDE4A0B 3D04030000              cmp eax, 00000304
:7FDE4A10 0F8499030000            je 7FDE4DAF

Hmmm....we can make a safe guess that these are only more checks on the characteristcs of the 
file...let's leave them alone...the jump we'll always take is the one at 4A05. Here's where it 
brings:

:7FDE4D4F 8B4730                  mov eax, dword ptr [edi+30] 
:7FDE4D52 85C0                    test eax, eax
:7FDE4D54 741C                    je 7FDE4D72
:7FDE4D56 53                      push ebx
:7FDE4D57 8D4DFC                  lea ecx, dword ptr [ebp-04]
:7FDE4D5A 6A00                    push 00000000
:7FDE4D5C 8D95E4FDFFFF            lea edx, dword ptr [ebp+FFFFFDE4]
:7FDE4D62 50                      push eax
:7FDE4D63 51                      push ecx
:7FDE4D64 52                      push edx
:7FDE4D65 E815690000              call 7FDEB67F        ; "RECYCLED ON/OFF" CHECK CALL          
:7FDE4D6A 85C0                    test eax, eax        ; EAX IS *ZERO* IF THE RECYCLED IS *OFF*
:7FDE4D6C 0F85ABFCFFFF            jne 7FDE4A1D         ; YOU GOT RECYCLED "ON", JUMP AND MOVE 
                                                       ; THE FILE TO IT
* Referenced by a JUMP at Address:
|:7FDE4D54(C)
|
:7FDE4D72 8D85E4FDFFFF            lea eax, dword ptr [ebp+FFFFFDE4] ; OTHERWISE PROCEED WITH
:7FDE4D78 50                      push eax                          ; THE PHYSICAL ELIMINATION 
* Reference To: SHELL32.Ordinal:00A4                                ; OF THE FILE!    
                                  |
:7FDE4D79 E8C7C3FFFF              call 7FDE1145
:7FDE4D7E 85C0                    test eax, eax
:7FDE4D80 7409                    je 7FDE4D8B
:7FDE4D82 C745FC00000000          mov [ebp-04], 00000000
:7FDE4D89 EB09                    jmp 7FDE4D94


Heh....looks like we found it :)
Everything depends on that "option check" call at 4D65...if the return value from the call (in 
eax) is ZERO, the file will be physically removed, otherwise it will be put in the recycled 
folder. You can look up what that call does by tracing into it...i personally wrote down every 
difference i found between the exectution with the "move to recyled" option (in the recycled 
preferences) switched ON and switched OFF....if you are interested, the code zone where the 
destiny of eax is decided is the one of the three jumps at B660, B666 and B66C. The xor will 
zero out eax and will give us back the zero value, avoiding the execution of quite some code in 
the call (which is needed to prepare the operation of moving the file to the recycled).
So, now we know that, in order to PHYSICALLY ELIMINATE the file, our program will have to 
perform the code that starts at 4D72...hey but what do i see here?? a jump that brings there?? 
hmm, let's put a bpx on this jump (7FDE4D54)...strange, it never jumps...neither with recycled 
"OFF", nor with recycled "ON"...ah! i almost forgot about our Good Old Redundand Code (TM) from 
Micro$oft :)))
No joke now, i must i say that this useless jump (will it jump once per millenium? ;) made me 
think about one thing...if there's a jump that avoids the whole previous piece of code (the one 
with those checks), this makes me sure about the meaning of the call at 4D65, and of its 
uselessiness (i don't know if that's correct in english :P) for our purpose...we don't have to 
worry about sticking in a flag and making the code check it AFTER the "option check" call...we 
can access the piece of code that erases the file from disk even AVOIDING the whole 
check....it's demonstrated by the fact that Microbloat programmers put a jump in the code that 
does exactly what we'll do now...AVOIDING the checks...it's just a matter of logic and 
intuition (but let's call it ZEN that makes me sound l33ter ;))....
The solution at this point is really easy...we'll modify the jump relative to the "NO" button 
in a way that it executes DIRECTLY the code at 7FDE4D72, instead of its useless functions! 
So, the first step is MAKING A BACKUP COPY OF YOUR SHELL32.DLL FILE, calling it shell32.bak for 
instance. Then, we'll also copy it to a new file that we'll physically patch (we can't patch 
shell32.dll cuz being a system dll it won't be discarded from memory while windows is running). 
Now we have 3 files, shell32.dll, shell32.bak and, let's say, shell32.new.

Logic (no zen this time;) would suggest us to write down the two offsets (one for the jump 
relative to the "NO" button, and one of the point where we want it to jump to), open HIEW and 
patch it as in every other case....instead the procedure we must follow is different. If you 
try this approach, when you'll restart Windows with the new shell32.dll, by pressing "NO" on 
the dialog you'll have the bitter delusion of a GPF....why?? the explanation is really easy, 
the reason alas not (to me at least:). I'd like it if someone told me why this problem occurs, 
anyway now i'll explain WHAT this problem is: when we patch shell32.dll with HIEW, the offset 
where we tell it to jump to is 34172h, but alas, at the execution of the jump in the "real life 
:)", the dll will jump to the code *VIRTUAL ADDRESS* 34172h, NOT to the *OFFSET* 34172h (which 
is relative to virtual address 7FDE4D72)....hmmm nasty problem you think?? nah, a little logic 
is enough to solve it...you should NEVER forget about the power of SoftICE...enter it and 
insert CODE ON (if you don't already have it in the init string)...this option will allow you 
to see the bytes relative to every single code line you're tracing through. Now put a bpx on 
7FDE4968 (the je relative to the "NO" button)...to break in the right code selector bpx on the 
usual DialogBoxParamA, then F12 to get to shell32.dll code. Once you put the bpx, press "NO" on 
the dialog box, and you'll find yourselves stuck on the line with the je where we placed the 
breakpoint. If you continue with execution, you'll cause a GPF, so what you do now is pressing 
the "A" key (Assemble instruction), so that sice will give you a nice prompt where you can 
insert the assembly instruction that you wish, and that will replace the current one. Just 
write "JE 7FDE4D72", and you'll note a change in the bytes at the left of the instruction. Take 
a piece of paper and write down those bytes. On my shell32.dll version the bytes are the 
following ones: 0F8404040000.
Once u did this, close everything and open your temporary file shell32.new with HIEW...go to 
offset 33D68h (F5), press F3 and insert the SAME EXACT byte sequence that SoftICE gave you 
before.
Save the file, restart in DOS mode, go to windows\system and copy SHELL32.NEW to SHELL32.DLL 
(that now is overwriteable, because Windows is not in execution). Now restart Windows...open 
explorer and try "delete" on a dummy file...if you press "ESC", the file will stay right 
there....if you press "YES", it will be moved to the recycled...and if you press "NO", the file 
will be removed from the disk! Yeah! We made it! :D

__________

With this tutorial i wanted to show how easy can it be to do some nice reversing, and i really 
hope that someone found all this useful for learning purposes. If you have any problems 
following the tute (not related to address differences i mean :), or you just want to make me 
know something (addons are PARTICULARLY welcome), my email is neural_noise@hotmail.com

This said, i wave to all the friends from #cracking4newbies, #crack-it and RingZ3r0 (welcome to 
the group, ALoR! :)...special greetings go to my dear friends BrahzVooz and ytc (thanks for 
hosting the tute, fella :))

till next time......!

-NeuRaL_NoiSE 1999